<route lang="json5">
	{
	style: {
	navigationStyle: 'custom',
	navigationBarTitleText: '脑波',
	enablePullDownRefresh: false,
	"app-plus": {
	"bounce": "none"
	}
	},
	}
</route>
<template>
	<view class="page">
		<view class="panel">
			<view class="nav-bar status_bar">
				<text class="iconfont icon-fanhui back" @click="backHandle"></text>
			</view>
			<view class="topic">
				<view class="title">
					<text v-if="setting.currentBrain">{{setting.currentBrain?.name}}</text>
					<text v-else>蓝牙连接</text>
				</view>
				<block v-if="!setting.currentBrain">
					<view class="tip" v-if="isAvailable">当前蓝牙可用</view>
					<view class="tip" v-else>当前蓝牙不可用,请打开</view>
				</block>
			</view>
			<view class="echarts" v-if="setting.currentBrain">
				<echarts :option="option" style="height: 300px"></echarts>
			</view>
			<view class="wrap" v-else  @click="showDeviceList">
				<view class="circle i1"></view>
				<view class="circle i2"></view>
				<view class="circle i3"></view>
				<view class="iconfont icon-blue blue"></view>
			</view>
			<view class="menu">
				<view class="row">
					<view class="item" @click="showDeviceList">
						<text v-if="!setting.currentBrain" @click="showDeviceList" class="iconfont icon-lanya1"
							:class="[setting.currentBrain?'on':'']"></text>
						<text v-else class="iconfont icon-qiehuan2" @click="deviceVisible = true"></text>
						<text class="label">{{setting.currentBrain?'已连接，可切换':'连接'}}</text>
					</view>
					<view class="item" @click="toConfig">
						<text class="iconfont icon-configure"></text>
						<text class="label">配置</text>
					</view>
				</view>
				<view class="row">
					<view class="item" @click="toHistory">
						<text class="iconfont icon-lishishuju1"></text>
						<text class="label">我的数据</text>
					</view>
					<view class="item" style="opacity:0.5;">
						<text class="iconfont icon-bangzhuzhongxin"></text>
						<text class="label">帮助</text>
					</view>
				</view>
			</view>
		</view>
		<th-dialog title="请选择设备" v-model:visible="deviceVisible">
			<template v-slot:content>
				<view class="device-list-wrap">
					<view class="device-list">
						<view v-for="d in setting.brainDevices" :key="d.deviceId" class="card"
							:class="[setting.currentBrain && d.deviceId === setting.currentBrain.deviceId?'on':'']"
							@click="connectBluetooth(d.deviceId)">
							<view class="name">{{d.name}}</view>
							<view v-if="setting.currentBrain && d.deviceId === setting.currentBrain.deviceId">
								已连接
							</view>
						</view>
					</view>
					<view v-if="!isAvailable" class="find">蓝牙未打开</view>
					<view v-if="isAvailable && isDiscovery" class="find">正在搜索设备···</view>
				</view>
			</template>
		</th-dialog>
	</view>

</template>

<script setup lang="ts">
	import { ab2hex, transformToArr, hexToDec } from './func'
	import echarts from '@/components/echarts.vue';
	import ThDialog from '@/pages/pm/assay-report/component/th-dialog.vue';
	import { voiceList } from '@/service/brain';
	import showModal from '@/utils/modal';
	import dayjs from "dayjs";

	import { useSetting } from '@/stores/setting';
	const setting = useSetting();
	const storageData = ref([])

	const backHandle = () => {
		uni.navigateBack({
			delta: 1
		});
	}
	const toConfig = () => {
		uni.navigateTo({
			url: '/pages/brainwave/config'
		})
	}
	
	const toHistory = () => {
		uni.navigateTo({
			url: '/pages/brainwave/history'
		})
    }
	/**
	 * 声音播放
	**/
	const innerAudioContext = uni.createInnerAudioContext();
	innerAudioContext.loop = true;
	const voiceListData = ref([]);

	const getVoiceList = () => {
		voiceList().then(res => {
			if (res.code === 0) {
				voiceListData.value = res.data.ruleList;
			}
		})
	}


	let changeUrl = '';
	const playVoice = (value : number) => {
		const matchVoice = voiceListData.value.find(item => value > item.min && value <= item.max);
		changeUrl = matchVoice?.voiceUrl;

		if (changeUrl && innerAudioContext.src !== changeUrl) {
			innerAudioContext.stop();
			innerAudioContext.src = changeUrl;
			innerAudioContext.play();
		}
	}

	/**
	 * 脑波图
	 * 
	**/

	let data = [];
	let now = new Date(1997, 9, 3);
	let oneDay = 24 * 3600 * 1000;
	let value = Math.random() * 1000;

	function randomData() {
		now = new Date(+now + oneDay);
		value = value + Math.random() * 21 - 10;
		return {
			name: now.toString(),
			value: [
				[now.getFullYear(), now.getMonth() + 1, now.getDate()].join('/'),
				0
			]
		};
	}

	for (var i = 0; i < 60; i++) {
		data.push(randomData());
	}

	const option = ref({
		id: 'wave001',
		grid: {
			show: false,
			right: 10,
			left: 5,
			containLabel: true,
			bottom: 10
		},
		xAxis: {
			type: 'time',
			show: false,
		},
		yAxis: {
			name: '单位：万',
			type: 'value',
			// max: 30,
			min: 0,
			axisLabel: {
				color: '#1ab3f5'
			},
			axisLine: {
				lineStyle: {
					color: '#1ab3f5'
				}
			},
			splitLine: {
				lineStyle: {
					color: '#1ab3f5'
				}
			}
		},
		series: [
			{
				data,
				type: 'line',
				symbol: 'none',
				smooth: true,
				lineStyle: {
					width: 1,
					color: "#fff"
				}
			}
		]
	});

	// #ifdef APP-PLUS

	/***
		是否正在搜索设备 isDiscovery
		设备是否连接
		特征是否可用
	**/

	const deviceVisible = ref(false);
	const isAvailable = ref(false);
	const isDiscovery = ref(false);

	// 初始化蓝牙
	const openBluetooth = () => {
		uni.openBluetoothAdapter({
			success: (e) => {
				//监听寻找到新设备的事件
				setting.onBrainDevices();
				if (e.errMsg == "openBluetoothAdapter:ok") {
					uni.getBluetoothAdapterState({
						success: function (res) {
							if (res.available) {
								//开始搜寻附近的蓝牙外围设备
								uni.stopBluetoothDevicesDiscovery()
								uni.startBluetoothDevicesDiscovery();
								isAvailable.value = true;
								isDiscovery.value = true;
							} else {
								uni.showToast({
									title: '本机蓝牙不可用',
									icon: 'none',
								});
								isAvailable.value = false;
							}
						},
					})
				}
			},
			fail: (err) => {
				isAvailable.value = false;
			}
		});
	}

	uni.onBluetoothAdapterStateChange((res) => {
		if (!res.available) {
			isAvailable.value = false;
		} else {
			if (!isAvailable.value) {
				openBluetooth();
			}
		}
	});

	// 监听设备断开
	uni.onBLEConnectionStateChange((res) => {
		if (!res.connected) {
			uni.setStorage({
				key: `brain_wave_${dayjs().format('YYYY-MM-DD HH:mm:ss')}`,
				data: JSON.stringify(storageData.value),
				success: function () {
					console.log('success');
				}
			})
			uni.closeBLEConnection({
				deviceId: res.deviceId,
				success() {
					clearEchart();
					innerAudioContext.stop();
					if (res.deviceId === setting.currentBrain.deviceId) {
						setting.currentBrain = null;
					}
				}
			})
		}
	});


	// 显示设备列表
	const showDeviceList = () => {
		if (!isAvailable.value) {
			uni.showToast({
				title: "请打开蓝牙",
				icon: 'none'
			});
		} else {
			deviceVisible.value = true;
		}
	}



	// 清空数据
	const clearEchart = () => {
		data = []
		for (var i = 0; i < 60; i++) {
			data.push(randomData());
		}

		option.value.series[0].data = data;
	}


	// 连接蓝牙
	const connectBluetooth = async (deviceId : string) => {
		if (setting.currentBrain) {
			// 阻止重复连接
			// if (setting.currentBrain.deviceId === deviceId) return;
			// 切换设备前先断开当前设备
			await breakConnect(setting.currentBrain.deviceId);
			clearEchart();
			if (setting.currentBrain.deviceId === deviceId) return;
			setting.currentBrain = null;
		};

		uni.showLoading({
			title: "正在连接",
			mask: true
		});
		//连接蓝牙
		uni.createBLEConnection({
			deviceId,
			timeout: 6000,
			success: async (res) => {
				// 获取设备所有服务
				const services = await getBLEServices(deviceId);
				// 查找所有特征值，增加到设备上
				await addCharacteristics(deviceId, services as [])
				// 找到能使用的特征值
				const device = setting.brainDevices.find((d) => d.deviceId === deviceId);
				if(!device.services.length || !device.characteristics.length){
					uni.hideLoading();
					uni.showToast({
						title:'设备不可用',
						icon:'none'
					})
					breakConnect(deviceId)
					return;
				}

				const characteristic = device.characteristics.filter(s => s.read)[0] || device.characteristics[0];
				// 监听
				const isNotify = await notify(characteristic, true);

				if (isNotify) {
					uni.hideLoading();
					setting.currentBrain = {
						...device,
						characteristicId: characteristic.characteristicId
					};
					deviceVisible.value = false;

					if (!setting.isNotify) {
						notifyChange();
					}
				}

			},
			fail(err) {
				uni.hideLoading();
				uni.showToast({
					title: '连接失败,请重试',
					icon: 'none'
				})
			}
		});
	}

	// 断开连接
	const breakConnect = (deviceId : string) => {
		return new Promise((resolve) => {
			uni.closeBLEConnection({
				deviceId,
				success() {
					resolve(true)
				},
				fail() {
					resolve(false)
				}
			})
		})
	}


	// 获取所有服务
	const getBLEServices = (deviceId : string) => {
		const getBLEDeviceServices = (resolve) => {
			uni.getBLEDeviceServices({
				deviceId,
				complete(res) {
					if (res.errMsg === "getBLEDeviceServices:ok" && res.services.length) {
						resolve(res.services)
					} else {
						getBLEDeviceServices(resolve)
					}
				}
			})
		}
		return new Promise((resolve) => {
			getBLEDeviceServices(resolve)
		})
	}

	// 补充所有服务的特征值
	const addCharacteristics = (deviceId : string, services : []) => {
		return new Promise(async (resolve) => {
			let characteristics = []
			for (var s = 0; s < services.length; s++) {
				const serviceId = services[s].uuid;
				const newCharacteristics = await getBLEDeviceCharacteristics({ deviceId, serviceId }) as [];
				characteristics = [...characteristics, ...newCharacteristics]
			}
			if (characteristics.length) {
				for (var index in setting.brainDevices) {
					if (setting.brainDevices[index].deviceId == deviceId) {
						setting.brainDevices[index].services = services;
						setting.brainDevices[index].characteristics = characteristics;
						break;
					}
				}
			}
			resolve(true)
		})
	}


	const getBLEDeviceCharacteristics = (param : any) => {
		return new Promise((resolve) => {
			uni.getBLEDeviceCharacteristics({
				...param,
				success(res) {
					const characteristics = res.characteristics.filter((c) => c.properties.notify).map((c) => {
						return {
							deviceId: param.deviceId,
							serviceId: param.serviceId,
							characteristicId: c.uuid,
							read: c.properties.read
						};
					})
					resolve(characteristics);
				},
				fail() {
					resolve(null);
				},
			});
		});
	};


	const notify = (param, state : boolean) => {
		return new Promise((resolve) => {
			uni.notifyBLECharacteristicValueChange({
				state, // 启用 notify 功能
				...param,
				success() {
					resolve(true)
				},
				fail(err) {
					resolve(false)
				}
			})
		})
	}



	const notifyChange = () => {
		let text : string;
		setting.isNotify = true;
		/* 监听低功耗蓝牙设备的特征值变化 */
		uni.onBLECharacteristicValueChange((CALLBACK) => {
			if (CALLBACK.characteristicId !== setting.currentBrain?.characteristicId) return;
			text += ab2hex(CALLBACK.value)
			if (/aaaa2002\w{2}8318/.test(text)) {
				const valueStr = text.substr(text.search(/aaaa2002\w{2}8318/), 72);
				if (valueStr.length === 72) {
					text = ''
					const [a1, a2, a3, b1, b2, b3] = transformToArr(valueStr);
					const total = hexToDec(a1) * 65536 + hexToDec(a2) * 256 + hexToDec(a3) + hexToDec(b1) * 65536 + hexToDec(b2) * 256 + hexToDec(b3);
					if (!isNaN(total)) {
						uni.$emit('notify', total)
					}
				}
			}
		})
	}

	onMounted(() => {
		getVoiceList()
		// 初始化蓝牙
		openBluetooth();
		uni.$off('notify')
		uni.$on('notify', (total) => {
			now = new Date(+now + oneDay);
			option.value.series[0].data.shift();
			option.value.series[0].data.push({
				name: now.toString(),
				value: [[now.getFullYear(), now.getMonth() + 1, now.getDate()].join('/'), total / 10000]
			});
			storageData.value.push(total)
			playVoice(total);
		})

		uni.$on('refresh', () => {
			getVoiceList();
		})
	})
	// #endif

	onBackPress(() => {
		if (!setting.currentBrain) return false;
		showModal({
			title: '提示',
			content: '设备正在连接中，确定要退出吗？',
			showCancel: true,
			confirm: async () => {
				innerAudioContext.destroy();
				uni.stopBluetoothDevicesDiscovery();
				await breakConnect(setting.currentBrain?.deviceId)
				setting.currentBrain = null;
				uni.navigateBack({
					delta: 1
				})
			},
		});
		return true;
	})
</script>

<style lang="scss" scoped>
	@import url('@/static/iconfont/iconfont.css');

	.page {
		height: 100vh;
	}

	.panel {
		background: linear-gradient(-45deg, #1ab3f5, #0081ff);
		height: 70vh;
		position: relative;
		.search,
		.back {
			color: #fff;
		}
		.nav-bar {
			padding: 0 30rpx;
			height: 100rpx;
			display: flex;
			align-items: center;
			justify-content: space-between;
		}
		.status_bar {
			padding-top: var(--status-bar-height);
			width: 100%;
		}
		.topic {
			color: #fff;
			text-align: center;
			.title {
				font-size: 38rpx;
				letter-spacing: 2rpx;
				font-weight: bold;
			}
			.tip {
				margin-top: 30rpx;
				font-size: 24rpx;
				letter-spacing: 2rpx;
				color: #f1f1f1;
			}
		}
	}

	.wrap {
		position: absolute;
		width: 520rpx;
		height: 520rpx;
		left: 50%;
		top: 360rpx;
		transform: translateX(-50%);
		.circle {
			border-radius: 50%;
			background: #fff;
			opacity: 0.1;
			position: absolute;
			left: 50%;
			transform: translateX(-50%);
			box-shadow: 0 0 10rpx 0 #1ab3f5;
		}
		.i1 {
			width: 100%;
			height: 100%;
		}

		.i2 {
			width: 75%;
			height: 75%;
			top: 12.5%;
			z-index: 9
		}

		.i3 {
			width: 50%;
			height: 50%;
			top: 25%;
			z-index: 99
		}

		.blue {
			top: 50%;
			left: 50%;
			position: absolute;
			transform: translate(-50%, -50%);
			color: #fff;
			font-size: 60rpx;
			animation:opac 0.8s linear infinite alternate ;
		}
	}
	
	@keyframes opac{
		from{
			opacity:1
		}to{
			opacity:0.2
		}
	}

	.menu {
		width: 570rpx;
		height: 320rpx;
		padding: 40rpx 60rpx;
		background: #fff;
		position: absolute;
		box-shadow: 0 0 10rpx 0 #e6e6e6;
		border-radius: 15rpx;
		bottom: -20%;
		left: 30rpx;
		.row {
			display: flex;
			height: 50%;
			.item {
				flex: 1;
				height: 100%;
				display: flex;
				flex-direction: column;
				align-items: center;
				justify-content: center;
				.iconfont {
					font-size: 50rpx;
					color: #333;
				}
				.label {
					font-size: 24rpx;
					margin-top: 15rpx;
					color: #333;
				}
				.icon-qiehuan2 {
					color: #1ab3f5;
				}
			}
		}
	}
    .device-list-wrap{
		display:flex;
		flex-direction:column;
		.device-list {
			padding: 0 20rpx;
			overflow-y: auto;
			flex:1;
			.card {
				padding: 20rpx;
				display: flex;
				align-items: center;
				border-radius: 8rpx;
				box-shadow: 0 0 10rpx 0 #e6e6e6;
				margin: 20rpx 0;
				justify-content: space-between;
				color: #333;
				&.on {
					color: #1890ff;
				}
				.name {
					font-weight: bold;
					padding-left: 80rpx;
					height: 60rpx;
					line-height: 60rpx;
					background: url(@/static/blue.png) no-repeat;
					background-size: 60rpx 60rpx;
					font-size: 36rpx;
				}
			}
		}
		.find {
			text-align: center;
			padding: 30rpx 0;
			color: #bfbfbf;
		}
	}
</style>